#include "config.h"

#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <getopt.h>
#include <dirent.h>
#include <ctype.h>

#include "configure.h"
#include "env.h"
#include "net_table.h"
#include "node.h"
#include "kv_event.h"
#include "../src/node_none.h"
#include "net_global.h"
#include "ylog.h"

typedef enum {
        OP_NULL,
        OP_CREATE,
        OP_LIST,
        OP_DELETE,
        OP_GET,
        OP_LOCK,
        OP_UNLOCK,
} admin_op_t;


static void usage()
{
        fprintf(stderr, "\nusage:\n"
                "kv --create namespace.bucket:value\n"
                "kv --list namespace.bucket\n"
                "kv --lock namespace.bucket:123456\n"
                "kv --unlock namespace.bucket:123456\n"
               );
}

static int __create(const nid_t *nid, const char *buf)
{
        int ret;
        char bucket[MAX_NAME_LEN], key[MAX_NAME_LEN], value[MAX_NAME_LEN];

        ret = sscanf(buf, "%[^.].%[^:]:%[^\n]", bucket, key, value);

        DINFO("buf %s, ret %u bucket %s key %s value %s\n", buf, ret, bucket, key, value);

        ret = kv_create(nid, bucket, key, value, strlen(value) + 1);
        if (unlikely(ret))
                GOTO(err_ret, ret);

        return 0;
err_ret:
        return ret;
}

static int __list(const nid_t *nid, const char *buf)
{
        int ret;
        char value[MAX_NAME_LEN];

        ret = kv_list(nid, buf, value);
        if (unlikely(ret))
                GOTO(err_ret, ret);

        printf("bucket %s list:\n%s", buf, value);

        return 0;
err_ret:
        return ret;
}

static int __lock(const nid_t *nid, const char *buf)
{
        int ret, locker;
        char bucket[MAX_NAME_LEN], key[MAX_NAME_LEN];

        ret = sscanf(buf, "%[^.].%[^:]:%d", bucket, key, &locker);

        DINFO("buf %s, ret %u bucket %s key %s locker %d\n", buf, ret, bucket, key, locker);

        ret = kv_lock(nid, bucket, key, locker);
        if (unlikely(ret))
                GOTO(err_ret, ret);

        return 0;
err_ret:
        return ret;
}


static int __unlock(const nid_t *nid, const char *buf)
{
        int ret, locker;
        char bucket[MAX_NAME_LEN], key[MAX_NAME_LEN];

        ret = sscanf(buf, "%[^.].%[^:]:%d", bucket, key, &locker);

        DINFO("buf %s, ret %u bucket %s key %s locker %d\n", buf, ret, bucket, key, locker);

        ret = kv_unlock(nid, bucket, key, locker);
        if (unlikely(ret))
                GOTO(err_ret, ret);

        return 0;
err_ret:
        return ret;
}



int main(int argc, char *argv[])
{
        int ret, op = OP_NULL;
        char c_opt;
        int verbose;
        char *name;
        net_handle_t nh;
        char buf[MAX_BUF_LEN];
        ynet_net_info_t *info;

        //dinfo_off();

        (void) verbose;

        while (srv_running) {
                int option_index = 0;

                static struct option long_options[] = {
                        { "create", required_argument, 0, 0},
                        { "list", required_argument, 0, 0},
                        { "delete", required_argument, 0, 0},
                        { "get", required_argument, 0, 0},
                        { "lock", required_argument, 0, 0},
                        { "unlock", required_argument, 0, 0},
                        { "verbose", 0, 0, 'v' },
                        { "help",    0, 0, 'h' },
                        { 0, 0, 0, 0 },
                };

                c_opt = getopt_long(argc, argv, "vh", long_options, &option_index);
                if (c_opt == -1)
                        break;

                switch (c_opt) {
                case 0:
                        switch (option_index) {
                        case 0:
                                DBUG("create\n");
                                op = OP_CREATE;
                                name = optarg;
                                break;
                        case 1:
                                DBUG("list\n");
                                op = OP_LIST;
                                name = optarg;
                                break;
                        case 2:
                                DBUG("delete\n");
                                op = OP_DELETE;
                                name = optarg;
                                break;
                        case 3:
                                DBUG("get\n");
                                op = OP_GET;
                                name = optarg;
                                break;
                        case 4:
                                DBUG("lock\n");
                                op = OP_LOCK;
                                name = optarg;
                                break;
                        case 5:
                                DBUG("unlock\n");
                                op = OP_UNLOCK;
                                name = optarg;
                                break;
                        default:
                                fprintf(stderr, "Hoops, wrong op got!\n");
                        }

                        break;
                case 'v':
                        verbose = 1;
                        break;
                case 'h':
                        usage();
                        EXIT(0);
                default:
                        usage();
                        EXIT(EINVAL);
                }
        }

#if 1
        if (argc == 1) {
                usage();
                EXIT(EINVAL);
        }
#endif

        ret = env_init_simple("lich.admin");
        if (unlikely(ret))
                GOTO(err_ret, ret);

        info = (void *)buf;
        ret = node_none_netinfo(info, "localhost:0");
        if (unlikely(ret))
                GOTO(err_ret, ret);

        ret = netable_connect_info(&nh, info);
        if (unlikely(ret))
                GOTO(err_ret, ret);


        if (op != OP_NULL) {
                switch (op) {
                case OP_CREATE:
                        ret = __create(&nh.u.nid, name);
                        if (unlikely(ret))
                                GOTO(err_ret, ret);

                        break;
                case OP_LIST:
                        ret = __list(&nh.u.nid, name);
                        if (unlikely(ret))
                                GOTO(err_ret, ret);

                        break;
                case OP_LOCK:
                        ret = __lock(&nh.u.nid, name);
                        if (unlikely(ret))
                                GOTO(err_ret, ret);

                        break;
                case OP_UNLOCK:
                        ret = __unlock(&nh.u.nid, name);
                        if (unlikely(ret))
                                GOTO(err_ret, ret);

                        break;
                case OP_DELETE:
                        break;
                case OP_GET:
                        break;
                default:
                        usage();
                        EXIT(EINVAL);
                }
        }

        return 0;
err_ret:
        EXIT(ret);
}
